{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Solving Multiple Tasks in a Sequence of Chats with Different Conversable Agent Pairs\n",
    "\n",
    "This notebook showcases how to use the new chat interface `autogen.initiate_chats` to solve a set of tasks with a sequence of chats. \n",
    "\n",
    "\\:\\:\\:info Requirements\n",
    "\n",
    "Install `ag2`:\n",
    "```bash\n",
    "pip install ag2[openai]\n",
    "```\n",
    "\n",
    "For more information, please refer to the [installation guide](https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/installing-ag2).\n",
    "\n",
    "\\:\\:\\:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import autogen\n",
    "\n",
    "config_list = autogen.config_list_from_json(env_or_file=\"OAI_CONFIG_LIST\")\n",
    "llm_config = {\"config_list\": config_list}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\\:\\:\\:tip\n",
    "\n",
    "Learn more about the various ways to configure LLM endpoints [here](https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/llm-configuration).\n",
    "\n",
    "\\:\\:\\:"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example Tasks\n",
    "Below are three example tasks, with each task being a string of text describing the request. The completion of later tasks requires or benefits from the results of previous tasks.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "financial_tasks = [\n",
    "    \"\"\"What are the current stock prices of NVDA and TESLA, and how is the performance over the past month in terms of percentage change?\"\"\",\n",
    "    \"\"\"Investigate possible reasons of the stock performance leveraging market news.\"\"\",\n",
    "]\n",
    "\n",
    "writing_tasks = [\"\"\"Develop an engaging blog post using any information provided.\"\"\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 1: Solve tasks with a series of chats\n",
    "\n",
    "The `autogen.initiate_chats` interface can take a list of dictionaries as inputs. Each dictionary preserves the following fields: \n",
    "\n",
    "- `sender`: a conversable agent as the sender;\n",
    "- `recipient`: a conversable agent as the recipient;\n",
    "- `message`: is a string of text (typically a message containing the task) or a callable;\n",
    "- `summary_method`: A string or a callable to get a summary from the chat. Currently supported choices include `last_msg`, which takes the last message from the chat history as the summary, and `reflection_with_llm`, which uses an LLM call to reflect on the chat history and summarize a takeaway;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "financial_assistant = autogen.AssistantAgent(\n",
    "    name=\"Financial_assistant\",\n",
    "    llm_config=llm_config,\n",
    ")\n",
    "research_assistant = autogen.AssistantAgent(\n",
    "    name=\"Researcher\",\n",
    "    llm_config=llm_config,\n",
    ")\n",
    "writer = autogen.AssistantAgent(\n",
    "    name=\"writer\",\n",
    "    llm_config=llm_config,\n",
    "    system_message=\"\"\"\n",
    "        You are a professional writer, known for\n",
    "        your insightful and engaging articles.\n",
    "        You transform complex concepts into compelling narratives.\n",
    "        Reply \"TERMINATE\" in the end when everything is done.\n",
    "        \"\"\",\n",
    ")\n",
    "\n",
    "user_proxy_auto = autogen.UserProxyAgent(\n",
    "    name=\"User_Proxy_Auto\",\n",
    "    human_input_mode=\"NEVER\",\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\") and x.get(\"content\", \"\").rstrip().endswith(\"TERMINATE\"),\n",
    "    code_execution_config={\n",
    "        \"last_n_messages\": 1,\n",
    "        \"work_dir\": \"tasks\",\n",
    "        \"use_docker\": False,\n",
    "    },  # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n",
    ")\n",
    "\n",
    "user_proxy = autogen.UserProxyAgent(\n",
    "    name=\"User_Proxy\",\n",
    "    human_input_mode=\"ALWAYS\",  # ask human for input at each step\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\") and x.get(\"content\", \"\").rstrip().endswith(\"TERMINATE\"),\n",
    "    code_execution_config={\n",
    "        \"last_n_messages\": 1,\n",
    "        \"work_dir\": \"tasks\",\n",
    "        \"use_docker\": False,\n",
    "    },  # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n",
    ")\n",
    "\n",
    "\n",
    "chat_results = autogen.initiate_chats([\n",
    "    {\n",
    "        \"sender\": user_proxy_auto,\n",
    "        \"recipient\": financial_assistant,\n",
    "        \"message\": financial_tasks[0],\n",
    "        \"clear_history\": True,\n",
    "        \"silent\": False,\n",
    "        \"summary_method\": \"last_msg\",\n",
    "    },\n",
    "    {\n",
    "        \"sender\": user_proxy_auto,\n",
    "        \"recipient\": research_assistant,\n",
    "        \"message\": financial_tasks[1],\n",
    "        \"max_turns\": 2,  # max number of turns for the conversation (added for demo purposes, generally not necessarily needed)\n",
    "        \"summary_method\": \"reflection_with_llm\",\n",
    "    },\n",
    "    {\n",
    "        \"sender\": user_proxy,\n",
    "        \"recipient\": writer,\n",
    "        \"message\": writing_tasks[0],\n",
    "        \"carryover\": \"I want to include a figure or a table of data in the blogpost.\",  # additional carryover to include to the conversation (added for demo purposes, generally not necessarily needed)\n",
    "    },\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Check chat results\n",
    "The `initiate_chat` method returns a `ChatResult` object, which is a dataclass object storing information about the chat. Currently, it includes the following attributes:\n",
    "\n",
    "- `chat_history`: a list of chat history.\n",
    "- `summary`: a string of chat summary. A summary is only available if a summary_method is provided when initiating the chat.\n",
    "- `cost`: a tuple of (total_cost, total_actual_cost), where total_cost is a dictionary of cost information, and total_actual_cost is a dictionary of information on the actual incurred cost with cache.\n",
    "- `human_input`: a list of strings of human inputs solicited during the chat. (Note that since we are setting `human_input_mode` to `NEVER` in this notebook, this list is always empty.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i, chat_res in enumerate(chat_results):\n",
    "    print(f\"*****{i}th chat*******:\")\n",
    "    print(chat_res.summary)\n",
    "    print(\"Human input in the middle:\", chat_res.human_input)\n",
    "    print(\"Conversation cost: \", chat_res.cost)\n",
    "    if i == 1:\n",
    "        assert len(chat_res.chat_history) == 4, (\n",
    "            f\"The chat history should contain at most 4 messages because max_turns is set to 2 in the {i}-th chat.\"\n",
    "        )\n",
    "    print(\"\\n\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 2: Solve a Sequence of Tasks involving User Defined Message\n",
    "\n",
    "In this example, say I have two tasks. One research task and a one writing task. The writing task needs data from research task. In this example, we direct read data from a file as part of the message."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "research_task = \"\"\"What are daily stock prices of NVDA and TESLA in the past month. Save the results in a .md file named 'stock_prices.md'.\"\"\"\n",
    "\n",
    "\n",
    "def my_writing_task(sender, recipient, context):\n",
    "    carryover = context.get(\"carryover\", \"\")\n",
    "    if isinstance(carryover, list):\n",
    "        carryover = carryover[-1]\n",
    "\n",
    "    try:\n",
    "        filename = context.get(\"work_dir\", \"\") + \"/stock_prices.md\"\n",
    "        with open(filename) as file:\n",
    "            data = file.read()\n",
    "    except Exception as e:\n",
    "        data = f\"An error occurred while reading the file: {e}\"\n",
    "\n",
    "    return (\n",
    "        \"\"\"Develop an engaging blog post using any information provided. \"\"\"\n",
    "        + \"\\nContext:\\n\"\n",
    "        + carryover\n",
    "        + \"\\nData:\"\n",
    "        + data\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "researcher = autogen.AssistantAgent(\n",
    "    name=\"Financial_researcher\",\n",
    "    llm_config=llm_config,\n",
    ")\n",
    "writer = autogen.AssistantAgent(\n",
    "    name=\"Writer\",\n",
    "    llm_config=llm_config,\n",
    "    system_message=\"\"\"\n",
    "        You are a professional writer, known for\n",
    "        your insightful and engaging articles.\n",
    "        You transform complex concepts into compelling narratives.\n",
    "        Reply \"TERMINATE\" in the end when everything is done.\n",
    "        \"\"\",\n",
    ")\n",
    "\n",
    "user_proxy_auto = autogen.UserProxyAgent(\n",
    "    name=\"User_Proxy_Auto\",\n",
    "    human_input_mode=\"NEVER\",\n",
    "    is_termination_msg=lambda x: x.get(\"content\", \"\") and x.get(\"content\", \"\").rstrip().endswith(\"TERMINATE\"),\n",
    "    code_execution_config={\n",
    "        \"last_n_messages\": 1,\n",
    "        \"work_dir\": \"tasks\",\n",
    "        \"use_docker\": False,\n",
    "    },  # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n",
    ")\n",
    "\n",
    "chat_results = autogen.initiate_chats([\n",
    "    {\n",
    "        \"sender\": user_proxy_auto,\n",
    "        \"recipient\": researcher,\n",
    "        \"message\": research_task,\n",
    "        \"clear_history\": True,\n",
    "        \"silent\": False,\n",
    "        \"summary_method\": \"last_msg\",\n",
    "    },\n",
    "    {\n",
    "        \"sender\": user_proxy_auto,\n",
    "        \"recipient\": writer,\n",
    "        \"message\": my_writing_task,\n",
    "        \"max_turns\": 2,  # max number of turns for the conversation (added for demo purposes, generally not necessarily needed)\n",
    "        \"summary_method\": \"reflection_with_llm\",\n",
    "        \"work_dir\": \"tasks\",\n",
    "    },\n",
    "])"
   ]
  }
 ],
 "metadata": {
  "front_matter": {
   "description": "Use AG2 to solve a set of tasks with a sequence of chats.",
   "tags": [
    "orchestration",
    "sequential chats"
   ]
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  },
  "vscode": {
   "interpreter": {
    "hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
